/*
 * Global.cs
 * 
 * Main entry point and other assembly-global features.
 */
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Jitsu
{
    public static class Global
    {
        private static Options s_options = null;

        [STAThread]
        public static int Main(string[] args)
        {
            Application.EnableVisualStyles();

            try
            {
                // Load defaults from app.config.
                s_options = new Options();

                // If args were spec'd on cmd line, use them; else show the GUI prompt.
                if (args.Length > 0)
                    return MainImplCmd(args);
                else
                    return MainImplGui();
            }
            catch (ApplicationException ex)
            {
                SafeConsoleColorSetter.SetColor(ConsoleColor.Red);
                Console.Error.WriteLine(ex.Message);
                SafeConsoleColorSetter.ResetColor();

                return CommandLine.ShowUsage();
            }
            catch (Exception ex)
            {
                SafeConsoleColorSetter.SetColor(ConsoleColor.Red);
                Console.Error.WriteLine(ex.ToString());
                SafeConsoleColorSetter.ResetColor();

                return 1;
            }
            finally
            {
                SafeConsoleColorSetter.ResetColor();
            }
        }

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        static int MainImplCmd(string[] args)
        {
            // Override default options with command line args.
            CommandLine.Parse(args, s_options);

            return MainImpl();
        }

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        static int MainImplGui()
        {
            // Obtain additional input from UI.
            PromptForArgs dlg = new PromptForArgs(s_options);
            if (dlg.ShowDialog() != DialogResult.OK)
                return 1;

            return MainImpl();
        }

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        static int MainImpl()
        {
            // Validate arguments.
            if (s_options.FilePattern == null || s_options.RegexPattern == null)
                throw new ApplicationException("Please specify at least a pathspec and regex pattern.");

            // Echo command line options.
            Console.Write(@"Searching directory ""{0}"", files ""{1}"", for pattern ""{2}"" (options: ",
                s_options.BaseDirectory, s_options.FilePattern, s_options.RegexPattern);

            System.Collections.ArrayList optionstrings = new System.Collections.ArrayList();

            if (s_options.RegexIgnoreCase)
                optionstrings.Add("IgnoreCase");
            if (s_options.RegexSingleline)
                optionstrings.Add("Singleline");
            if (s_options.RegexMimicVS)
                optionstrings.Add("RegexMimicVS");
            if (s_options.ReplacementText != null)
                optionstrings.Add(String.Format("Replacement pattern: {0}", s_options.ReplacementText));

            if (optionstrings.Count == 0)
                optionstrings.Add("none");

            Console.Write(String.Join(", ", (string[])optionstrings.ToArray(typeof(string))));
            Console.WriteLine(")");

            // Reimplement VS's most useful helper patterns: C identifiers, number literals, and quoted strings.
            if (s_options.RegexMimicVS)
            {
                s_options.RegexPattern = s_options.RegexPattern.Replace("::", "\x003A");
                s_options.RegexPattern = s_options.RegexPattern.Replace(":i", @"(\b[_a-zA-Z][_a-zA-Z0-9]*\b)");
                s_options.RegexPattern = s_options.RegexPattern.Replace(":n", @"(\b[0-9]+(\.[0-9]+)?([Ee](\+|-)?[0-9]+)?\b)");
                s_options.RegexPattern = s_options.RegexPattern.Replace(":q", @"((@""(""""|[^""])*"")|(""(\\.|[^""\\])*""))");
            }

            // Create the regex, and populate the visitor callback with it.
            RegexOptions ro = RegexOptions.Compiled | RegexOptions.Multiline;
            if (s_options.RegexIgnoreCase)
                ro |= RegexOptions.IgnoreCase;
            if (s_options.RegexSingleline)
                ro |= RegexOptions.Singleline;

            FileVisitor visitor = new FileVisitor();
            visitor.UserRegex = new Regex(s_options.RegexPattern, ro);
            visitor.ReplacementText = s_options.ReplacementText;

            visitor.OutputWidth = s_options.OutputWidth;

            // Do the dew!
            Jitsu.IO.DirectoryTraverser.FileVisitor onFile =
                new Jitsu.IO.DirectoryTraverser.FileVisitor(visitor.VisitFile);
            Jitsu.IO.DirectoryTraverser spider =
                new Jitsu.IO.DirectoryTraverser(null, onFile);

            string directoryPattern = (s_options.DoRecursion) ? "*" : String.Empty;
            spider.TraverseBreadthFirst(s_options.BaseDirectory, s_options.FilePattern, directoryPattern);

            // Report the totals.
            SafeConsoleColorSetter.ResetColor();
            Console.WriteLine();
            Console.WriteLine("Total found: {0}    Matching files: {1}    Total files searched: {2}",
                visitor.MatchesFound, visitor.FilesFound, visitor.FilesSearched);

            // Done.
            return 0;
        }
    }
}